/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */


/**
 *
 * @author subGroup2
 */
public class Emulator {

    int PC;
    short MDR;
    Code ram = new Code();
    Register reg = new Register();
    Arithmetic arithmetic = new Arithmetic(ram, reg);

    public void run_once() {
        MDR = fetch();
        reg.setIR(MDR);
        this.decode_execute(MDR);
    }

    public void run_until_ret() {
        do {
            MDR = fetch();
            reg.setIR(MDR);
            this.decode_execute(MDR);
        } while (MDR != 218 && MDR != 219);
    }

    public void decode_execute(short opcode) {
        switch (opcode) {
            case 0: // 0x00:  NOP
                // No Operation
                break;
            case 1: // 0x01:  reserved
                // currently unallocated opcode - treat as NOP
                break;
            case 2: // 0x02:  reserved
                // currently unallocated opcode - treat as NOP
                break;
            case 3: // 0x03:  reserved
                // currently unallocated opcode - treat as NOP
                break;
            case 4: // 0x04:  reserved
                // currently unallocated opcode - treat as NOP
                break;
            case 5: // 0x05:  reserved
                // currently unallocated opcode - treat as NOP
                break;
            case 6: // 0x06:  reserved
                // currently unallocated opcode - treat as NOP
                break;
            case 7: // 0x07:  reserved
                // currently unallocated opcode - treat as NOP
                break;
            case 8: // 0x08:  SET C
                reg.setC(1);  // Set carry bit to 1
                break;
            case 9: // 0x09:  CLR C
                reg.setC(0);  // Set carry bit to 0
                break;
            case 10: // 0x0A:  SET BS
                reg.setBS(1);  // Switch to register bank 1
                break;
            case 11: // 0x0B:  CLR BS
                reg.setBS(0);  // Switch to register bank 0
                break;
            case 12: // 0x0C:  SET IE
                reg.setIE(1);  // Enable interrupts
                break;
            case 13: // 0x0D:  CLR IE
                reg.setIE(0);  // Disable interrupts
                break;
            case 14: // 0x0E:  CPL C
                arithmetic.cplC();  // Complement carry bit
                break;
            case 15: // 0x0F:  CPL A
                arithmetic.cplA();  // Complement accumulator
                break;
            case 16: // 0x10:  XCSD
                arithmetic.xcsd();  // Exchange SP with DPTR
                break;
            case 17: // 0x11:  SFA
                reg.setA(reg.getFLAGS());  // Store flags to accumulator
                break;
            case 18: // 0x12:  LAF
                reg.setFLAGS(reg.getA());  // Load accumulator to flags
                break;
            case 19: // 0x13: MOV DPTR, SP
                reg.setDPTR(reg.getSP());  // Move word SP to DPTR
                break;
            case 20: // 0x14: MOV SP, DPTR
                reg.setSP(reg.getDPTR());  // Move word DPTR to SP
                break;
            case 21: // 0x15: MOV A, #data8
                reg.setA(MDR = fetch());  // Move immediate byte to accumulator
                break;
            case 22: // 0x16: MOV SP, #data16
                // Move immediate word to SP
                reg.setSPH(MDR = fetch());  // Move first byte to SPH
                reg.setSPL(MDR = fetch());  // Move first byte to SPL
                break;
            case 23: // 0x17: MOV DPTR, #data16
                // Move immediate word to DPTR
                reg.setDPH(MDR = fetch());  // Move first byte to DPH
                reg.setDPL(MDR = fetch());  // Move first byte to DPL
                break;
            case 24: // 0x18: MOV A, addr16
                reg.setA(arithmetic.getDirectData());  // Move data from direct address to accumulator
                break;
            case 25: // 0x19: MOV addr16, A
                arithmetic.setData(reg.getA());  // Move data from accumulator to direct address
                break;
            case 26: // 0x1A: MOV A, @A+DPTR
                reg.setA(arithmetic.getRelativeData(reg.getA(), reg.getDPTR()));  // Indexed move relative to DPTR to accumulator
                break;
            case 27: // 0x1B: MOV A, @A+PC
                reg.setA(arithmetic.getRelativeData(reg.getA(), reg.getPC()));  // Indexed move relative to PC to accumulator
                break;
            case 28: // 0x1C: MOV A, @addr16
                reg.setA(arithmetic.getIndirectData());  // Move data from indirect address to accumulator
                break;
            case 29: // 0x1D: MOV @addr16, A
                arithmetic.setIndirectData(reg.getA());  // Move data from accumulator to indirect address
                break;
            case 30: // 0x1E: MOV A, @DPTR
                reg.setA(arithmetic.getRelativeData((short) 0, reg.getDPTR()));  //  Register indirect move to accumulator
                break;
            case 31: // 0x1F: MOV @DPTR, A
                arithmetic.set2DPTR(reg.getA());  //  Register indirect move from accumulator
                break;
            case 32: // 0x20: MOV @DPTR, R0
                arithmetic.set2DPTR(reg.getR0());  //  Register indirect move from R0
                break;
            case 33: // 0x21: MOV @DPTR, R1
                arithmetic.set2DPTR(reg.getR1());  //  Register indirect move from R1
                break;
            case 34: // 0x22: MOV @DPTR, R2
                arithmetic.set2DPTR(reg.getR2());  //  Register indirect move from R2
                break;
            case 35: // 0x23: MOV @DPTR, R3
                arithmetic.set2DPTR(reg.getR3());  //  Register indirect move from R3
                break;
            case 36: // 0x24: MOV @DPTR, DPH
                arithmetic.set2DPTR(reg.getDPH());  //  Register indirect move from DPH
                break;
            case 37: // 0x25: MOV @DPTR, DPL
                arithmetic.set2DPTR(reg.getDPL());  //  Register indirect move from DPL
                break;
            case 38: // 0x26: MOV @DPTR, SPH
                arithmetic.set2DPTR(reg.getSPH());  //  Register indirect move from SPH
                break;
            case 39: // 0x27: MOV @DPTR, DPH
                arithmetic.set2DPTR(reg.getSPL());  //  Register indirect move from SPL
                break;
            case 40: // 0x28: MOV R0, #data
                reg.setR0(MDR = fetch());  // Move immediate byte to R0
                break;
            case 41: // 0x29: MOV R1, #data
                reg.setR1(MDR = fetch());  // Move immediate byte to R1
                break;
            case 42: // 0x2A: MOV R2, #data
                reg.setR2(MDR = fetch());  // Move immediate byte to R2
                break;
            case 43: // 0x2B: MOV R3, #data
                reg.setR3(MDR = fetch());  // Move immediate byte to R3
                break;
            case 44: // 0x2C: MOV DPH, #data
                reg.setDPH(MDR = fetch());  // Move immediate byte to DPH
                break;
            case 45: // 0x2D: MOV DPL, #data
                reg.setDPL(MDR = fetch());  // Move immediate byte to DPL
                break;
            case 46: // 0x2E: MOV SPH, #data
                reg.setSPH(MDR = fetch());  // Move immediate byte to SPH
                break;
            case 47: // 0x2F: MOV SPL, #data
                reg.setSPL(MDR = fetch());  // Move immediate byte to SPL
                break;
            case 48: // 0x30: MOV R0, A
                reg.setR0(reg.getA());  // A -> R0
                break;
            case 49: // 0x31: MOV R1, A
                reg.setR1(reg.getA());  // A -> R1
                break;
            case 50: // 0x32: MOV R2, A
                reg.setR2(reg.getA());  // A -> R2
                break;
            case 51: // 0x33: MOV R3, A
                reg.setR3(reg.getA());  // A -> R3
                break;
            case 52: // 0x34: MOV DPH, A
                reg.setDPH(reg.getA());  // A -> DPH
                break;
            case 53: // 0x35: MOV DPL, A
                reg.setDPL(reg.getA());  // A -> DPL
                break;
            case 54: // 0x36: MOV SPH, A
                reg.setSPH(reg.getA());  // A -> SPH
                break;
            case 55: // 0x37: MOV SPL, A
                reg.setSPL(reg.getA());  // A -> SPL
                break;
            case 56: // 0x38: MOV A, R0
                reg.setA(reg.getR0());  // R0 -> A
                break;
            case 57: // 0x39: MOV A, R1
                reg.setA(reg.getR1());  // R1 -> A
                break;
            case 58: // 0x3A: MOV A, R2
                reg.setA(reg.getR2());  // R2 -> A
                break;
            case 59: // 0x3B: MOV A, R3
                reg.setA(reg.getR3());  // R3 -> A
                break;
            case 60: // 0x3C: MOV A, DPH
                reg.setA(reg.getDPH());  // DPH -> A
                break;
            case 61: // 0x3D: MOV A, DPL
                reg.setA(reg.getDPL());  // DPL -> A
                break;
            case 62: // 0x3E: MOV A, SPH
                reg.setA(reg.getSPH());  // SPH -> A
                break;
            case 63: // 0x3F: MOV A, SPL
                reg.setA(reg.getSPL());  // SPL -> A
                break;
            case 64: // 0x40: MOV R0, @DPTR
                reg.setR0(arithmetic.getRelativeData((short) 0, reg.getDPTR()));  //  Register indirect move to R0
                break;
            case 65: // 0x41: MOV R0, R1
                reg.setR0(reg.getR1());  // R1 -> R0
                break;
            case 66: // 0x42: MOV R0, R2
                reg.setR0(reg.getR2());  // R2 -> R0
                break;
            case 67: // 0x43: MOV R0, R3
                reg.setR0(reg.getR3());  // R3 -> R0
                break;
            case 68: // 0x44: MOV R0, DPH
                reg.setR0(reg.getDPH());  // DPH -> R0
                break;
            case 69: // 0x45: MOV R0, DPL
                reg.setR0(reg.getDPL());  // DPL -> R0
                break;
            case 70: // 0x46: MOV R0, SPH
                reg.setR0(reg.getSPH());  // SPH -> R0
                break;
            case 71: // 0x47: MOV R0, SPL
                reg.setR0(reg.getSPL());  // SPL -> R0
                break;
            case 72: // 0x48: MOV R1, R0
                reg.setR1(reg.getR0());  // R0 -> R1
                break;
            case 73: // 0x49: MOV R1, @DPTR
                reg.setR1(arithmetic.getRelativeData((short) 0, reg.getDPTR()));  //  Register indirect move to R1
                break;
            case 74: // 0x4A: MOV R1, R2
                reg.setR1(reg.getR2());  // R2 -> R1
                break;
            case 75: // 0x4B: MOV R1, R3
                reg.setR1(reg.getR3());  // R3 -> R1
                break;
            case 76: // 0x4C: MOV R1, DPH
                reg.setR1(reg.getDPH());  // DPH -> R1
                break;
            case 77: // 0x4D: MOV R1, DPL
                reg.setR1(reg.getDPL());  // DPL -> R1
                break;
            case 78: // 0x4E: MOV R1, SPH
                reg.setR1(reg.getSPH());  // SPH -> R1
                break;
            case 79: // 0x4F: MOV R1, SPL
                reg.setR1(reg.getSPL());  // SPL -> R1
                break;
            case 80: // 0x50: MOV R2, R0
                reg.setR2(reg.getR0());  // R0 -> R2
                break;
            case 81: // 0x51: MOV R2, R1
                reg.setR2(reg.getR1());  // R1 -> R2
                break;
            case 82: // 0x52: MOV R2, @DPTR
                reg.setR2(arithmetic.getRelativeData((short) 0, reg.getDPTR()));  //  Register indirect move to R2
                break;
            case 83: // 0x53: MOV R2, R3
                reg.setR2(reg.getR3());  // R3 -> R2
                break;
            case 84: // 0x54: MOV R2, DPH
                reg.setR2(reg.getDPH());  // DPH -> R2
                break;
            case 85: // 0x55: MOV R2, DPL
                reg.setR2(reg.getDPL());  // DPL -> R2
                break;
            case 86: // 0x56: MOV R2, SPH
                reg.setR2(reg.getSPH());  // SPH -> R2
                break;
            case 87: // 0x57: MOV R2, SPL
                reg.setR2(reg.getSPL());  // SPL -> R2
                break;
            case 88: // 0x58: MOV R3, R0
                reg.setR3(reg.getR0());  // R0 -> R3
                break;
            case 89: // 0x59: MOV R3, R1
                reg.setR3(reg.getR1());  // R1 -> R3
                break;
            case 90: // 0x5A: MOV R3, R2
                reg.setR3(reg.getR2());  // R2 -> R3
                break;
            case 91: // 0x5B: MOV R3, @DPTR
                reg.setR3(arithmetic.getRelativeData((short) 0, reg.getDPTR()));  //  Register indirect move to R3
                break;
            case 92: // 0x5C: MOV R3, DPH
                reg.setR3(reg.getDPH());  // DPH -> R3
                break;
            case 93: // 0x5D: MOV R3, DPL
                reg.setR3(reg.getDPL());  // DPL -> R3
                break;
            case 94: // 0x5E: MOV R3, SPH
                reg.setR3(reg.getSPH());  // SPH -> R3
                break;
            case 95: // 0x5F: MOV R3, SPL
                reg.setR3(reg.getSPL());  // SPL -> R3
                break;
            case 96: // 0x60: MOV DPH, R0
                reg.setDPH(reg.getR0());  // R0 -> DPH
                break;
            case 97: // 0x61: MOV DPH, R1
                reg.setDPH(reg.getR1());  // R1 -> DPH
                break;
            case 98: // 0x62: MOV DPH, R2
                reg.setDPH(reg.getR2());  // R2 -> DPH
                break;
            case 99: // 0x63: MOV DPH, R3
                reg.setDPH(reg.getR3());  // R3 -> DPH
                break;
            case 100: // 0x64: MOV DPH, @DPTR
                reg.setDPH(arithmetic.getRelativeData((short) 0, reg.getDPTR()));  //  Register indirect move to DPH
                break;
            case 101: // 0x65: MOV DPH, DPL
                reg.setDPH(reg.getDPL());  // DPL -> DPH
                break;
            case 102: // 0x66: MOV DPH, SPH
                reg.setDPH(reg.getSPH());  // SPH -> DPH
                break;
            case 103: // 0x67: MOV DPH, SPL
                reg.setDPH(reg.getSPL());  // SPL -> DPH
                break;
            case 104: // 0x68: MOV DPL, R0
                reg.setDPL(reg.getR0());  // R0 -> DPL
                break;
            case 105: // 0x69: MOV DPL, R1
                reg.setDPL(reg.getR1());  // R1 -> DPL
                break;
            case 106: // 0x6A: MOV DPL, R2
                reg.setDPL(reg.getR2());  // R2 -> DPL
                break;
            case 107: // 0x6B: MOV DPL, R3
                reg.setDPL(reg.getR3());  // R3 -> DPL
                break;
            case 108: // 0x6C: MOV DPL, DPH
                reg.setDPL(reg.getDPH());  // DPH -> DPL
                break;
            case 109: // 0x6D: MOV DPL, @DPTR
                reg.setDPL(arithmetic.getRelativeData((short) 0, reg.getDPTR()));  //  Register indirect move to DPL
                break;
            case 110: // 0x6E: MOV DPL, SPH
                reg.setDPL(reg.getSPH());  // SPH -> DPL
                break;
            case 111: // 0x6F: MOV DPL, SPL
                reg.setDPL(reg.getSPL());  // SPL -> DPL
                break;
            case 112: // 0x70: MOV SPH, R0
                reg.setSPH(reg.getR0());  // R0 -> SPH
                break;
            case 113: // 0x71: MOV SPH, R1
                reg.setSPH(reg.getR1());  // R1 -> SPH
                break;
            case 114: // 0x72: MOV SPH, R2
                reg.setSPH(reg.getR2());  // R2 -> SPH
                break;
            case 115: // 0x73: MOV SPH, R3
                reg.setSPH(reg.getR3());  // R3 -> SPH
                break;
            case 116: // 0x74: MOV SPH, DPH
                reg.setSPH(reg.getDPH());  // DPH -> SPH
                break;
            case 117: // 0x75: MOV SPH, DPL
                reg.setSPH(reg.getDPL());  // DPL -> SPH
                break;
            case 118: // 0x76: MOV SPH, @DPTR
                reg.setSPH(arithmetic.getRelativeData((short) 0, reg.getDPTR()));  //  Register indirect move to SPH
                break;
            case 119: // 0x77: MOV SPH, SPL
                reg.setSPH(reg.getSPL());  // SPL -> SPH
                break;
            case 120: // 0x78: MOV SPL, R0
                reg.setSPL(reg.getR0());  // R0 -> SPL
                break;
            case 121: // 0x79: MOV SPL, R1
                reg.setSPL(reg.getR1());  // R1 -> SPL
                break;
            case 122: // 0x7A: MOV SPL, R2
                reg.setSPL(reg.getR2());  // R2 -> SPL
                break;
            case 123: // 0x7B: MOV SPL, R3
                reg.setSPL(reg.getR3());  // R3 -> SPL
                break;
            case 124: // 0x7C: MOV SPL, DPH
                reg.setSPL(reg.getDPH());  // DPH -> SPL
                break;
            case 125: // 0x7D: MOV SPL, DPL
                reg.setSPL(reg.getDPL());  // DPL -> SPL
                break;
            case 126: // 0x7E: MOV SPL, SPH
                reg.setSPL(reg.getSPH());  // SPH -> SPL
                break;
            case 127: // 0x7F: MOV SPL, @DPTR
                reg.setSPL(arithmetic.getRelativeData((short) 0, reg.getDPTR()));  //  Register indirect move to SPL
                break;
            case 128: // 0x80: ANL A, R0
                reg.setA(arithmetic.AND(reg.getA(), reg.getR0()));  //  A and R0 -> A
                break;
            case 129: // 0x81: ANL A, R1
                reg.setA(arithmetic.AND(reg.getA(), reg.getR1()));  // A and R1 -> A
                break;
            case 130: // 0x82: ANL A, R2
                reg.setA(arithmetic.AND(reg.getA(), reg.getR2()));  // A and R2 -> A
                break;
            case 131: // 0x83: ANL A, R3
                reg.setA(arithmetic.AND(reg.getA(), reg.getR3()));  // A and R3 -> A
                break;
            case 132: // 0x84: ANL A, DPH
                reg.setA(arithmetic.AND(reg.getA(), reg.getDPH()));  // A and R4 -> A
                break;
            case 133: // 0x85: ANL A, DPL
                reg.setA(arithmetic.AND(reg.getA(), reg.getDPL()));  // A and R5 -> A
                break;
            case 134: // 0x86: ANL A, #data8
                reg.setA(arithmetic.AND(reg.getA(), MDR = fetch()));  // A and #data8 -> A
                break;
            case 135: // 0x87: ANL A, @DPTR
                reg.setA(arithmetic.AND(reg.getA(), ram.getRAM(reg.getDPTR())));  // A and main[DPTR] -> A
                break;
            case 136:  // 0x88: ORL A, R0
                reg.setA(arithmetic.OR(reg.getA(), reg.getR0()));  //  A or R0 -> A
                break;
            case 137: // 0x89: ORL A, R1
                reg.setA(arithmetic.OR(reg.getA(), reg.getR1()));  //  A or R1 -> A
                break;
            case 138: // 0x8A: ORL A, R2
                reg.setA(arithmetic.OR(reg.getA(), reg.getR2()));  //  A or R2 -> A
                break;
            case 139: // 0x8B: ORL A, R3
                reg.setA(arithmetic.OR(reg.getA(), reg.getR3()));  //  A or R3 -> A
                break;
            case 140: // 0x8C: ORL A, DPH
                reg.setA(arithmetic.OR(reg.getA(), reg.getDPH()));  //  A or DPH -> A
                break;
            case 141: // 0x8D: ORL A, DPL
                reg.setA(arithmetic.OR(reg.getA(), reg.getDPL()));  //  A or DPL -> A
                break;
            case 142: // 0x8E: ORL A, #data8
                reg.setA(arithmetic.OR(reg.getA(), MDR = fetch()));  // A or #data8 -> A
                break;
            case 143: // 0x8F: ORL A, @DPTR
                reg.setA(arithmetic.OR(reg.getA(), ram.getRAM(reg.getDPTR())));  // A or main[DPTR] -> A
                break;
            case 144: // 0x90: XRL A, R0
                reg.setA(arithmetic.XOR(reg.getA(), reg.getR0()));  //  A xor R0 -> A
                break;
            case 145: // 0x91: XRL A, R1
                reg.setA(arithmetic.XOR(reg.getA(), reg.getR1()));  //  A xor R1 -> A
                break;
            case 146: // 0x92: XRL A, R2
                reg.setA(arithmetic.XOR(reg.getA(), reg.getR2()));  //  A xor R2 -> A
                break;
            case 147: // 0x93: XRL A, R3
                reg.setA(arithmetic.XOR(reg.getA(), reg.getR3()));  //  A xor R3 -> A
                break;
            case 148: // 0x94: XRL A, DPH
                reg.setA(arithmetic.XOR(reg.getA(), reg.getDPH()));  //  A xor DPH -> A
                break;
            case 149: // 0x95: XRL A, DPL
                reg.setA(arithmetic.XOR(reg.getA(), reg.getDPL()));  //  A xor DPL -> A
                break;
            case 150: // 0x96: XRL A, #data8
                reg.setA(arithmetic.XOR(reg.getA(), MDR = fetch()));  // A xor #data8 -> A
                break;
            case 151: // 0x97: XRL A, @DPTR
                reg.setA(arithmetic.XOR(reg.getA(), ram.getRAM(reg.getDPTR())));  // A xor main[DPTR] -> A
                break;
            case 152: // 0x98: RL A
                reg.setA(arithmetic.RL(reg.getA()));  // Rotate accumulator left
                break;
            case 153: // 0x99: RLC A
                reg.setA(arithmetic.RLC(reg.getA()));  // Rotate accumulator left through carry
                break;
            case 154: // 0x9A: RR A
                reg.setA(arithmetic.RR(reg.getA()));  // Rotate accumulator right
                break;
            case 155: // 0x9B: RRC A
                reg.setA(arithmetic.RRC(reg.getA()));  // Rotate accumulator right through carry
                break;
            case 156: // 0x9C: INC DPTR
                if(reg.getDPTR()==0xffff)
                    reg.setDPTR(0);
                else
                    reg.setDPTR(reg.getDPTR() + 1);	// DPTR + 1 -> DPTR
                break;
            case 157: // 0x9D:  DEC DPTR
                if(reg.getDPTR()==0)
                    reg.setDPTR(0xffff);
                else
                    reg.setDPTR(reg.getDPTR() - 1); // DPTR - 1 -> DPTR
                break;
            case 158: // 0x9E:  INC A
                if(reg.getA()==0xff){
                    reg.setA(0);
                    reg.setC(1);
                }
                else
                    reg.setA(reg.getA() + 1);  // A + 1 -> A
                break;
            case 159: // 0x9F:  DEC A
                if(reg.getA()==0){
                    reg.setA(0xff);
                    reg.setC(1);
                }
                else
                    reg.setA(reg.getA() - 1);  // A - 1 -> A
                break;
            case 160: // 0xA0:  ADD A, R0
                reg.setA(arithmetic.ADD(reg.getA(), reg.getR0()));  // A + R0 -> A
                break;
            case 161: // 0xA1:  ADD A, R1
                reg.setA(arithmetic.ADD(reg.getA(), reg.getR1()));  // A + R1 -> A
                break;
            case 162: // 0xA2:  ADD A, R2
                reg.setA(arithmetic.ADD(reg.getA(), reg.getR2()));  // A + R2 -> A
                break;
            case 163: // 0xA3:  ADD A, R3
                reg.setA(arithmetic.ADD(reg.getA(), reg.getR3()));  // A + R3 -> A
                break;
            case 164: // 0xA4:  ADD A, DPH
                reg.setA(arithmetic.ADD(reg.getA(), reg.getDPH()));  // A + DPH -> A
                break;
            case 165: // 0xA5:  ADD A, DPL
                reg.setA(arithmetic.ADD(reg.getA(), reg.getDPL()));  // A + DPL -> A
                break;
            case 166: // 0xA6:  ADD A, #data8
                reg.setA(arithmetic.ADD(reg.getA(), MDR = fetch()));  // A + data8 -> A
                break;
            case 167: // 0xA7:  ADD A, @DPTR
                reg.setA(arithmetic.ADD(reg.getA(), ram.getRAM(reg.getDPTR())));  // A + main[DPTR] -> A
                break;
            case 168: // 0xA8:  ADDC A, R0
                reg.setA(arithmetic.ADDC(reg.getA(), reg.getR0()));  // A + R0 + CY -> A
                break;
            case 169: // 0xA9:  ADDC A, R1
                reg.setA(arithmetic.ADDC(reg.getA(), reg.getR1()));  // A + R1 + CY -> A
                break;
            case 170: // 0xAA:  ADDC A, R2
                reg.setA(arithmetic.ADDC(reg.getA(), reg.getR2()));  // A + R2 + CY -> A
                break;
            case 171: // 0xAB:  ADDC A, R3
                reg.setA(arithmetic.ADDC(reg.getA(), reg.getR3()));  // A + R3 + CY -> A
                break;
            case 172: // 0xAC:  ADDC A, DPH
                reg.setA(arithmetic.ADDC(reg.getA(), reg.getDPH()));  // A + DPH + CY -> A
                break;
            case 173: // 0xAD:  ADDC A, DPL
                reg.setA(arithmetic.ADDC(reg.getA(), reg.getDPL()));  // A + DPL + CY -> A
                break;
            case 174: // 0xAE:  ADDC A, #data8
                reg.setA(arithmetic.ADDC(reg.getA(), MDR = fetch()));  // A + data8 + CY -> A
                break;
            case 175: // 0xAF:  ADDC A, @DPTR
                reg.setA(arithmetic.ADDC(reg.getA(), ram.getRAM(reg.getDPTR())));  // A + main[DPTR] + CY -> A
                break;
            case 176: // 0xB0:  SUB A, R0
                reg.setA(arithmetic.SUB(reg.getA(), reg.getR0()));  // A - R0 -> A
                break;
            case 177: // 0xB1:  SUB A, R1
                reg.setA(arithmetic.SUB(reg.getA(), reg.getR1()));  // A - R1 -> A
                break;
            case 178: // 0xB2:  SUB A, R2
                reg.setA(arithmetic.SUB(reg.getA(), reg.getR2()));  // A - R2 -> A
                break;
            case 179: // 0xB3:  SUB A, R3
                reg.setA(arithmetic.SUB(reg.getA(), reg.getR3()));  // A - R3 -> A
                break;
            case 180: // 0xB4:  SUB A, DPH
                reg.setA(arithmetic.SUB(reg.getA(), reg.getDPH()));  // A - DPH -> A
                break;
            case 181: // 0xB5:  SUB A, DPL
                reg.setA(arithmetic.SUB(reg.getA(), reg.getDPL()));  // A - DPL -> A
                break;
            case 182: // 0xB6:  SUB A, #data8
                reg.setA(arithmetic.SUB(reg.getA(), MDR = fetch()));  // A - data8 -> A
                break;
            case 183: // 0xB7:  SUB A, @DPTR
                reg.setA(arithmetic.SUB(reg.getA(), ram.getRAM(reg.getDPTR())));  // A - main[DPTR] -> A
                break;
            case 184: // 0xB8:  SUBB A, R0
                reg.setA(arithmetic.SUBB(reg.getA(), reg.getR0()));  // A - R0 - CY -> A
                break;
            case 185: // 0xB9:  SUBB A, R1
                reg.setA(arithmetic.SUBB(reg.getA(), reg.getR1()));  // A - R1 - CY -> A
                break;
            case 186: // 0xBA:  SUBB A, R2
                reg.setA(arithmetic.SUBB(reg.getA(), reg.getR2()));  // A - R2 - CY -> A
                break;
            case 187: // 0xBB:  SUBB A, R3
                reg.setA(arithmetic.SUBB(reg.getA(), reg.getR3()));  // A - R3 - CY -> A
                break;
            case 188: // 0xBC:  SUBB A, DPH
                reg.setA(arithmetic.SUBB(reg.getA(), reg.getDPH()));  // A - DPH - CY -> A
                break;
            case 189: // 0xBD:  SUBB A, DPL
                reg.setA(arithmetic.SUBB(reg.getA(), reg.getDPL()));  // A - DPL - CY -> A
                break;
            case 190: // 0xBE:  SUBB A, #data8
                reg.setA(arithmetic.SUBB(reg.getA(), MDR = fetch()));  // A - data8 - CY -> A
                break;
            case 191: // 0xBF:  SUBB A, @DPTR
                reg.setA(arithmetic.SUBB(reg.getA(), ram.getRAM(reg.getDPTR())));  // A - main[DPTR] - CY -> A
                break;
            case 192: // 0xC0:  PJMP addr11
                arithmetic.PJMP(0, MDR = fetch());  // Page Jump [PC(15:11) 0 0 0 addr8]
                break;
            case 193: // 0xC1:  PJMP addr11
                arithmetic.PJMP(1, MDR = fetch());  // Page Jump [PC(15:11) 0 0 1 addr8]
                break;
            case 194: // 0xC2:  PJMP addr11
                arithmetic.PJMP(2, MDR = fetch());  // Page Jump [PC(15:11) 0 1 0 addr8]
                break;
            case 195: // 0xC3:  PJMP addr11
                arithmetic.PJMP(3, MDR = fetch());  // Page Jump [PC(15:11) 0 1 1 addr8]
                break;
            case 196: // 0xC4:  PJMP addr11
                arithmetic.PJMP(4, MDR = fetch());  // Page Jump [PC(15:11) 1 0 0 addr8]
                break;
            case 197: // 0xC5:  PJMP addr11
                arithmetic.PJMP(5, MDR = fetch());  // Page Jump [PC(15:11) 1 0 1 addr8]
                break;
            case 198: // 0xC6:  PJMP addr11
                arithmetic.PJMP(6, MDR = fetch());  // Page Jump [PC(15:11) 1 1 0 addr8]
                break;
            case 199: // 0xC7:  PJMP addr11
                arithmetic.PJMP(7, MDR = fetch());  // Page Jump [PC(15:11) 1 1 1 addr8]
                break;
            case 200: // 0xC8:  PCALL addr11
                arithmetic.PCALL(0, MDR = fetch());  // Page Call [PC(15:11) 0 0 0 addr8]
                break;
            case 201: // 0xC9:  PCALL addr11
                arithmetic.PCALL(1, MDR = fetch());  // Page Call [PC(15:11) 0 0 1 addr8]
                break;
            case 202: // 0xCA:  PCALL addr11
                arithmetic.PCALL(2, MDR = fetch());  // Page Call [PC(15:11) 0 1 0 addr8]
                break;
            case 203: // 0xCB:  PCALL addr11
                arithmetic.PCALL(3, MDR = fetch());  // Page Call [PC(15:11) 0 1 1 addr8]
                break;
            case 204: // 0xCC:  PCALL addr11
                arithmetic.PCALL(4, MDR = fetch());  // Page Call [PC(15:11) 1 0 0 addr8]
                break;
            case 205: // 0xCD:  PCALL addr11
                arithmetic.PCALL(5, MDR = fetch());  // Page Call [PC(15:11) 1 0 1 addr8]
                break;
            case 206: // 0xCE:  PCALL addr11
                arithmetic.PCALL(6, MDR = fetch());  // Page Call [PC(15:11) 1 1 0 addr8]
                break;
            case 207: // 0xCF:  PCALL addr11
                arithmetic.PCALL(7, MDR = fetch());  // Page Call [PC(15:11) 1 1 1 addr8]
                break;
            case 208: // 0xD0:  DJNZ R0, rel8
                reg.setR0(reg.getR0() - 1);  // Decrement R0
                if (reg.getR0() != 0) // Jump if not zero
                {
                    reg.setPC((this.fetch() + PC) % 65536);  // Jump to PC + rel8
                }
                else
                    this.fetch();
                break;
            case 209: // 0xD1:  DJNZ R1, rel8
                reg.setR1(reg.getR1() - 1);  // Decrement R1
                if (reg.getR1() != 0) // Jump if not zero
                {
                    reg.setPC((this.fetch() + PC) % 65536);  // Jump to PC + rel8
                }
                else
                    this.fetch();
                break;
            case 210: // 0xD2:  DJNZ R2, rel8
                reg.setR2(reg.getR2() - 1);  // Decrement R2
                if (reg.getR2() != 0) // Jump if not zero
                {
                    reg.setPC((this.fetch() + PC) % 65536);  // Jump to PC + rel8
                }
                else
                    this.fetch();
                break;
            case 211: // 0xD3:  DJNZ R3, rel8
                reg.setR3(reg.getR3() - 1);  // Decrement R0
                if (reg.getR3() != 0) // Jump if not zero
                {
                    reg.setPC((this.fetch() + PC) % 65536);  // Jump to PC + rel8
                }
                else
                    this.fetch();
                break;
            case 212: // 0xD4:  CJNZ R0, #data, rel8
                if (reg.getR0() != this.fetch()) // Compare R0 with data8 and jump if no equal
                {
                    reg.setPC((this.fetch() + PC) % 65536);  // Jump to PC + rel8
                }
                else
                    this.fetch();
                break;
            case 213: // 0xD5:  CJNZ R1, #data, rel8
                if (reg.getR1() != this.fetch()) // Compare R1 with data8 and jump if no equal
                {
                    reg.setPC((this.fetch() + PC) % 65536);  // Jump to PC + rel8
                }
                else
                    this.fetch();
                break;
            case 214: // 0xD6:  CJNZ R2, #data, rel8
                if (reg.getR2() != this.fetch()) // Compare R2 with data8 and jump if no equal
                {
                    reg.setPC((this.fetch() + PC) % 65536);  // Jump to PC + rel8
                }
                else
                    this.fetch();
                break;
            case 215: // 0xD7:  CJNZ R3, #data, rel8
                if (reg.getR3() != this.fetch()) // Compare R3 with data8 and jump if no equal
                {
                    reg.setPC((this.fetch() + PC) % 65536);  // Jump to PC + rel8
                }
                else
                    this.fetch();
                break;
            case 216: // 0xD8:  LJMP addr16
                arithmetic.LJMP(MDR = this.fetch(),MDR = this.fetch());  // first addr8 -> PCH, second addr8 -> PCL
                break;
            case 217: // 0xD9:  LCALL addr16
                arithmetic.LCALL(MDR = this.fetch(),MDR = this.fetch()); // Push current PC+2 and first addr8 -> PCH, second addr8 -> PCL
                break;
            case 218: // 0xDA:  RET
                arithmetic.popPC();  // Return from subroutine
                break;
            case 219: // 0xDB:  RETI
                // Return from interrupt
                break;
            case 220: // 0xDC:  SJMP
                reg.setPC((this.fetch() + PC) % 65536);  // Relative jump to PC + rel8
                break;
            case 221: // 0xDD:  JMP @A+DPTR
                reg.setPC((reg.getA() + reg.getDPTR()) % 65536);  // Indexed indirect jump relative to DPTR
                break;
            case 222: // 0xDE:  JMP @DPTR
                reg.setPC(reg.getDPTR());  // Jump indirect to DPTR
                break;
            case 223: // 0xDF: CJNE A, #data8, rel8
                if (reg.getA() != this.fetch()) // Compare A with data8 and jump if no equal
                {
                    reg.setPC((this.fetch() + PC) % 65536);  // Jump to PC + rel8
                }
                else
                    this.fetch();
                break;
            case 224: // 0xE0: JZ rel8
                if (reg.getZ() == 1) // Jump if zero
                {
                    reg.setPC((this.fetch() + PC) % 65536);  // Relative jump to PC + rel8
                }
                else
                    this.fetch();
                break;
            case 225: // 0xE1: JNZ rel8
                if (reg.getZ() == 0) // Jump if not zero
                {
                    reg.setPC((this.fetch() + PC) % 65536);  // Relative jump to PC + rel8
                }
                else
                    this.fetch();
                break;
            case 226: // 0xE2: JC rel8
                if (reg.getC() == 1) // Jump if carry
                {
                    reg.setPC((this.fetch() + PC) % 65536);  // Relative jump to PC + rel8
                }
                else
                    this.fetch();
                break;
            case 227: // 0xE3: JNC rel8
                if (reg.getC() == 0) // Jump if not carry
                {
                    reg.setPC((this.fetch() + PC) % 65536);  // Relative jump to PC + rel8
                }
                else
                    this.fetch();
                break;
            case 228: // 0xE4: JPO rel8
                if (reg.getP() == 1) // Jump if parity odd
                {
                    reg.setPC((this.fetch() + PC) % 65536);  // Relative jump to PC + rel8
                }
                else
                    this.fetch();
                break;
            case 229: // 0xE5: JPE rel8
                if (reg.getP() == 0) // Jump if parity even
                {
                    reg.setPC((this.fetch() + PC) % 65536);  // Relative jump to PC + rel8
                }
                else
                    this.fetch();
                break;
            case 230: // 0xE6: JS rel8
                if (reg.getS() == 1) // Jump if sign (negative)
                {
                    reg.setPC((this.fetch() + PC) % 65536);  // Relative jump to PC + rel8
                }
                else
                    this.fetch();
                break;
            case 231: // 0xE7: JNS rel8
                if (reg.getS() == 0) // Jump if not sign (positive)
                {
                    reg.setPC((this.fetch() + PC) % 65536);  // Relative jump to PC + rel8
                }
                else
                    this.fetch();
                break;
            case 232: // 0xE8:  PUSH R0
                arithmetic.PUSH(reg.getR0());  // Push R0 to the stack
                break;
            case 233: // 0xE9:  PUSH R1
                arithmetic.PUSH(reg.getR1());  // Push R1 to the stack
                break;
            case 234: // 0xEA:  PUSH R2
                arithmetic.PUSH(reg.getR2());  // Push R2 to the stack
                break;
            case 235: // 0xEB:  PUSH R3
                arithmetic.PUSH(reg.getR3());  // Push R3 to the stack
                break;
            case 236: // 0xEC:  PUSH DPH
                arithmetic.PUSH(reg.getDPH());  // Push DPH to the stack
                break;
            case 237: // 0xED:  PUSH DPL
                arithmetic.PUSH(reg.getDPL());  // Push DPL to the stack
                break;
            case 238: // 0xEE:  PUSH A
                arithmetic.PUSH(reg.getA());  // Push A to the stack
                break;
            case 239: // 0xEF:  PUSH FLAGS
                arithmetic.PUSH(reg.getFLAGS());  // Push FLAGS to the stack
                break;
            case 240: // 0xF0:  POP R0
                reg.setR0(arithmetic.POP());  // Pop top off stack to R0
                break;
            case 241: // 0xF1:  POP R1
                reg.setR1(arithmetic.POP());  // Pop top off stack to R1
                break;
            case 242: // 0xF2:  POP R2
                reg.setR2(arithmetic.POP());  // Pop top off stack to R2
                break;
            case 243: // 0xF3:  POP R3
                reg.setR3(arithmetic.POP());  // Pop top off stack to R3
                break;
            case 244: // 0xF4:  POP DPH
                reg.setDPH(arithmetic.POP());  // Pop top off stack to DPH
                break;
            case 245: // 0xF5:  POP DPL
                reg.setDPL(arithmetic.POP());  // Pop top off stack to DPL
                break;
            case 246: // 0xF6:  POP A
                reg.setA(arithmetic.POP());  // Pop top off stack to A
                break;
            case 247: // 0xF7:  POP FLAGS
                reg.setFLAGS(arithmetic.POP());  // Pop top off stack to FLAGS
                break;
            case 248: // 0xF8:  MUL R0, R1
                arithmetic.MUL_R0_R1();  // R0 * R1 -> {R0 R1}
                break;
            case 249: // 0xF9:  DIV R0, R1
                arithmetic.DIV_R0_R1();	 // R0 % R1 -> {R0 R1}
                break;
            case 250: // 0xFA:  DA A
                arithmetic.DA_A();  // Decimal adjust accumulator
                break;
            case 251: // 0xFB:  reserved
                // currently unallocated opcode - treat as NOP
                break;
            case 252: // 0xFC:  IN A, port_addr
                // Input value on I/O port 'port_addr' to accumulator
                break;
            case 253: // 0xFD:  OUT port_addr, A
                // Output accumulator value to I/O port 'port_addr'
                break;
            case 254: // 0xFE:  IN vect8
                // Software interrupt at vector vect8
                break;
            case 255: // 0xFF:  HLT
                reg.decreasePC(); // Halt processor
                break;
        }

    }

    private short fetch() {
        this.PC = this.reg.getPC();
        this.reg.increasePC();
        return this.ram.getRAM(PC);
    }

    public void reset() {
        reg.reset();
    }

    public static void main(String[] args) {
        Emulator test = new Emulator();
        /*System.out.println(test.reg.getA());
        test.reg.setA(test.MDR = test.fetch());
        System.out.println(test.MDR);
        System.out.println(test.reg.getA());
        test.reg.setA(test.MDR = test.fetch());
        System.out.println(test.MDR);
        System.out.println(test.reg.getA());
        test.reg.setA(test.MDR = test.fetch());
        System.out.println(test.MDR);
        System.out.println(test.reg.getA());*/
        test.run_once();
        System.out.println(test.MDR);
    }
}
